DefaultBatchInsert.java
package org.codefilarete.stalactite.engine.crud;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.LongStream;
import org.codefilarete.stalactite.sql.ConnectionProvider;
import org.codefilarete.stalactite.sql.Dialect;
import org.codefilarete.stalactite.sql.ddl.structure.Column;
import org.codefilarete.stalactite.sql.ddl.structure.Table;
import org.codefilarete.stalactite.sql.order.ColumnVariable;
import org.codefilarete.stalactite.sql.order.Insert;
import org.codefilarete.stalactite.sql.order.InsertCommandBuilder;
import org.codefilarete.stalactite.sql.order.InsertCommandBuilder.InsertStatement;
import org.codefilarete.stalactite.sql.statement.WriteOperation;
import org.codefilarete.tool.collection.Iterables;
import org.codefilarete.tool.collection.KeepOrderSet;
import static org.codefilarete.tool.function.Predicates.not;
/**
*
* @param <T> table type
* @author Guillaume Mary
*/
public class DefaultBatchInsert<T extends Table<T>> extends Insert<T> implements BatchInsert<T> {
private final List<Set<ColumnVariable<?, T>>> rows = new ArrayList<>();
private final Dialect dialect;
private final ConnectionProvider connectionProvider;
public DefaultBatchInsert(T targetTable, Dialect dialect, ConnectionProvider connectionProvider) {
super(targetTable);
this.dialect = dialect;
this.connectionProvider = connectionProvider;
}
@Override
public <C> DefaultBatchInsert<T> set(Column<? extends T, C> column, C value) {
super.set(column, value);
return this;
}
@Override
public BatchInsert<T> newRow() {
rows.add(new KeepOrderSet<>(getRow()));
getRow().clear();
return this;
}
@Override
public long execute() {
// treating remaining values in case user didn't call newRow(..)
if (!getRow().isEmpty()) {
rows.add(new KeepOrderSet<>(getRow()));
}
InsertStatement<T> insertStatement = new InsertCommandBuilder<>(this, dialect).toStatement();
long[] writeCount;
try (WriteOperation<Column<T, ?>> writeOperation = dialect.getWriteOperationFactory().createInstance(insertStatement, connectionProvider)) {
this.rows.stream()
// avoiding empty rows made by several calls to newRow(..) without setting values. Can happen if insert(..) is reused in a loop.
.filter(not(Set::isEmpty))
.<Map<Column<T, ?>, ?>>map(row -> Iterables.map(row, ColumnVariable::getColumn, ColumnVariable::getValue))
.forEach(writeOperation::addBatch);
writeCount = writeOperation.executeBatch();
}
// we clear current rows to let one reuse this instance
rows.clear();
getRow().clear();
return LongStream.of(writeCount).sum();
}
}